package com.df.my_net_game.game_rpc.config;

import com.df.my_net_game.game_rpc.client.GRpcClientCenter;
import com.df.my_net_game.game_rpc.client.annotation.GRpc;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;

import java.lang.reflect.Method;

public class GRpcClientFactoryBean <T> implements SmartFactoryBean<T> , ApplicationContextAware {
    ApplicationContext applicationContext;
    private Class<T> grpcClientInterface;
//    private RkproblemHelperProvider provider;
//    private static final Map<String, Map<String, MethodInformation>> interfaceProcessorMap = new ConcurrentHashMap(4);

    public GRpcClientFactoryBean(Class<T> grpcClientInterface) {
        this.grpcClientInterface = grpcClientInterface;
    }
    @Override
    public T getObject() throws Exception {
        this.checkBeanIsInterface();
        //TODO 预编译了的化就直接加载类，不生成了，参考lombok的编译
        DynamicType.Unloaded<Object> make = new ByteBuddy()
                .subclass(Object.class)
                .implement(grpcClientInterface)
                .name(grpcClientInterface.getName()+"$RpcClient")
                .method(ElementMatchers.isDeclaredBy(grpcClientInterface))
                .intercept(MethodDelegation.to(GRpcClientCenter.class))
                .make();
//        make.saveIn(new File(grpcClientInterface.getClassLoader().getResource("").getPath()));
        //收集每个方法的元信息
        GRpc annotation = grpcClientInterface.getAnnotation(GRpc.class);

        Method[] declaredMethods = grpcClientInterface.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            GRpcClientCenter.addReqMethod(grpcClientInterface,declaredMethod,annotation);
        }
        Class<?> loaded = make.load(grpcClientInterface.getClassLoader())
                .getLoaded();
        return (T) loaded.getDeclaredConstructor().newInstance();
//        return (T) Proxy.newProxyInstance(this.grpcClientInterface.getClassLoader(), new Class[]{this.grpcClientInterface},(Object proxy, Method method, Object[] args)->{
//            //TODO 调用远程方法
//            //消息id 参数 返回值
//            System.out.println(777);
//            return null;
//        });
    }

    private void checkBeanIsInterface() {
        Assert.isTrue(this.grpcClientInterface.isInterface(), "@Rpc 只能作用在接口类型上！");
    }

    @Override
    public Class<?> getObjectType() {
        return grpcClientInterface;
    }

    @Override
    public boolean isPrototype() {
        return true;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}
